#include <string.h>
#include "gkt_board.h"
#include "gkt_os.h"
#include "gkt_debug.h"
#include "gkt_driver.h"
#include "gkt_key.h"
#include "gkt_fpsensor.h"
#include "gkt_rfid.h"
#include "window_common.h"
#include "gkt_adc.h"
#include "gkt_network.h"
#include "window_factory_inspect.h"
#include "gkt_card.h"

#if defined(GKT_CONFIG_FACTORY_INSPECT_ENABLE) && GKT_CONFIG_FACTORY_INSPECT_ENABLE

#if defined(GKT_CONFIG_NETWORK_ENABLE) && GKT_CONFIG_NETWORK_ENABLE &&	\
	defined(GKT_CONFIG_NETWORK_FACTORY_INSPECT_ENABLE) && GKT_CONFIG_NETWORK_FACTORY_INSPECT_ENABLE
#define WINDOW_FACTORY_INSPECT_NETWORK_ENABLE 1
#else
#define WINDOW_FACTORY_INSPECT_NETWORK_ENABLE 0
#endif
#ifdef GKT_CONFIG_WINDOW_FACTORY_INSPECT_START_NEXT_INTERVAL
#define WINDOW_FACTORY_INSPECT_START_NEXT_INTERVAL	\
	GKT_CONFIG_WINDOW_FACTORY_INSPECT_START_NEXT_INTERVAL
#else
#define WINDOW_FACTORY_INSPECT_START_NEXT_INTERVAL	1000
#endif

enum {
	WIDGET_ID_LIST = 0,
	WIDGET_ID_MAX
};

static const gkt_widget_list_attr_s sc_window_factory_inspect_list_attr = 
	GKT_WIDGET_LIST_STATIC_ATTR(0, NULL);

GKT_WINDOW_WIDGET_DESCS_DEFINE(factory_inspect) = {
	[WIDGET_ID_LIST] = GKT_WIDGET_LIST_DESC(
										0, 
										&sc_window_factory_inspect_list_attr),					
};


enum {
	TEST_ITEM_BATTERY_CALI,
	TEST_ITEM_KEY,
	TEST_ITEM_FPSENSOR,
	TEST_ITEM_CARD,
	TEST_ITEM_RFID,
	TEST_ITEM_KEY_FREQS,
#if  (!defined(GKT_CONFIG_KEYPAD_SPT5115S_ENABLE) || !GKT_CONFIG_KEYPAD_SPT5115S_ENABLE)	\
	&& defined(GKT_CONFIG_KEYPAD_NO_CONNECT_CHANNEL)
	TEST_ITEM_NO_CONNECT_KEY_FREQS,
#endif	
#if WINDOW_FACTORY_INSPECT_NETWORK_ENABLE
	TEST_ITEM_NETWORK,
#endif
	TEST_ITEM_AON32K,
	TEST_ITEM_MAX
};

enum {
	TIMER_ID_START = 0,
	TIMER_ID_DO,
	TIMER_ID_TIMEOUT,
	TIMER_ID_VOICE_TIMEOUT,
	TIMER_ID_EXIT,
	TIMER_ID_MAX
};

typedef struct _window_factory_inspect {
	uint32_t	init_params;
	uint32_t	major_stage;
	uint32_t	minor_stage;
	uint32_t	err_bits;
	int err_bits_ids;
	int	skip_subsequent_stage;
} window_factory_inspect_s;
static window_factory_inspect_s window_factory_inspect;

typedef int (*window_factory_inspect_init_fn)(uint32_t data);
typedef int (*window_factory_inspect_do_fn)(uint32_t data);
typedef struct _window_factory_inspect_item {
	window_factory_inspect_init_fn	init_fn;
	window_factory_inspect_do_fn	do_fn;
	uint32_t	minor_stage_max;
	uint32_t	do_interval;
	uint32_t	timeout;
} window_factory_inspect_item_s;
#define WINDOW_FACTORY_INSPECT_ITEM_DEFINE(UC_ITEM_NAME, lc_item_name)	\
	[TEST_ITEM_##UC_ITEM_NAME] = {	\
		.init_fn	= window_factory_inspect_##lc_item_name##_init,	\
		.do_fn	= window_factory_inspect_##lc_item_name##_do,	\
		.minor_stage_max	= WINDOW_FACTORY_INSPECT_##UC_ITEM_NAME##_MINOR_STAGE_MAX,	\
		.do_interval	= WINDOW_FACTORY_INSPECT_##UC_ITEM_NAME##_DO_INTERVAL,	\
		.timeout	= WINDOW_FACTORY_INSPECT_##UC_ITEM_NAME##_TIMEOUT,	\
	}
/************************************************************
 * BATTERY CALI
 ************************************************************/
#define	FACTORY_POWER_MAX_CNT	24
static uint16_t window_factory_inspect_get_power_avg(void)
{
	uint8_t dev_id = 0;
	gkt_adc_attr_s adc_attr;
	uint32_t time_ms,cnt,i,adc_sum,adc_cnt;
	uint16_t adc_value[32],adc_max,adc_min,adc_avg;
	int retval, value;

	adc_attr.channel = ADC_USED_CHANNEL;
	adc_attr.mode = ADC_GPIO;//ADC_VINLPM
	adc_attr.scale_type = ADC_Scale_1200Mv;
	gkt_adc_config(dev_id, &adc_attr);
	
	time_ms = gkt_systime_ms();
	time_ms += 20;
	cnt = 0;
	do{
		retval = gkt_adc_start(0, &value);
		if (retval == GKT_SUCCESS) {
			gkt_printf("!!!adc_val=%d\n", value);
			adc_value[cnt] = (uint16_t)value;
		}
		cnt++;
		gkt_delay_ms(1);
		if(cnt > FACTORY_POWER_MAX_CNT)
			break;
	} while(gkt_systime_ms() < time_ms);
	
	adc_max = 0;
	adc_min = 0xffff;
	adc_sum = 0;
	adc_cnt = 0;
	for(i=0;i<cnt;i++){
		adc_sum += adc_value[i];
		adc_cnt++;
		if(adc_value[i] >= adc_max)
			adc_max = adc_value[i];

		if(adc_value[i] <= adc_min)
			adc_min = adc_value[i];
	}

	adc_avg = 0;
	if(adc_cnt >= 3){
		adc_sum = adc_sum - adc_max - adc_min;
		adc_sum = adc_sum/(adc_cnt-2);
		adc_avg = (uint16_t)adc_sum;
	}
	
	return adc_avg;
}

static int window_factory_inspect_battery_get_adc_suc(void)
{
	uint16_t adc_value[3],adc_value_avg,adc_base_value;
	int adc_offset;

	if (WINDOW_OPCODE_COMPATIBLE_FACTORY_INSPECT_3791 == window_factory_inspect.init_params) {
		adc_value[0] = window_factory_inspect_get_power_avg();
		adc_value[1] = window_factory_inspect_get_power_avg();
		adc_value[2] = window_factory_inspect_get_power_avg();
		adc_value_avg = (adc_value[0] + adc_value[1] + adc_value[2])/3;
		
		adc_base_value = adc_value_avg * GKT_CONFIG_BATTERY_RESISTOR_VALUE / 1000;
		gkt_printf("FACTORY_INSPECT: adc_value_avg = %d base_value=%d\n", adc_value_avg, adc_base_value);
		if ((adc_base_value < GKT_CONFIG_BATTERY_FACTORY_INSPECT_MV_MIN) 
			|| (adc_base_value > GKT_CONFIG_BATTERY_FACTORY_INSPECT_MV_MAX)) {
			gkt_error("!!!adc_voltage error min: %d max:%d current:%d mv\n",GKT_CONFIG_BATTERY_FACTORY_INSPECT_MV_MIN,
						GKT_CONFIG_BATTERY_FACTORY_INSPECT_MV_MAX, adc_base_value);
#if defined(GKT_CONFIG_BATTERY_FACTORY_INSPECT_DEVELOPER_MODE) && GKT_CONFIG_BATTERY_FACTORY_INSPECT_DEVELOPER_MODE
			return GKT_SUCCESS;
#else
			return GKT_AGING_TEST_EPOWER;
#endif
		}
		
		adc_offset = adc_base_value - GKT_CONFIG_BATTERY_FACTORY_INSPECT_MV_BASE;
		gp_window_unreset_data->adc_adjust_value = adc_offset;
		gkt_printf("FACTORY_INSPECT: BATTERY ADC OFFSET = %d\n", adc_offset);

		window_data_save();
	}

	return GKT_SUCCESS;
}

static int window_factory_inspect_battery_cali_init(uint32_t data)
{
	int retval;

	retval = window_factory_inspect_battery_get_adc_suc();
	gkt_unused(data);
	if (retval != GKT_SUCCESS)
		gkt_error("battery err=%d\n",retval);
	return retval;
}
#define window_factory_inspect_battery_cali_do	NULL
#define WINDOW_FACTORY_INSPECT_BATTERY_CALI_MINOR_STAGE_MAX	1
#define WINDOW_FACTORY_INSPECT_BATTERY_CALI_DO_INTERVAL	0
#define WINDOW_FACTORY_INSPECT_BATTERY_CALI_TIMEOUT	0

/************************************************************
 * KEY
 ************************************************************/
static uint32_t s_window_factory_inspect_key_freq_table[GKT_CONFIG_KEYPAD_CHANNEL_NUMS];
#ifdef GKT_CONFIG_FACTORY_INSPECT_KEY_DELTA_MIN
#define WINDOW_FACTORY_INSPECT_KEY_DELTA_MIN	GKT_CONFIG_FACTORY_INSPECT_KEY_DELTA_MIN
#else
#define WINDOW_FACTORY_INSPECT_KEY_DELTA_MIN	15000
#endif
static uint32_t s_factory_inspect_key_ok_nums = 0;
#if GKT_CONFIG_DEBUG_ENABLE
static void window_factory_inspect_key_show_freqs(uint32_t *freq_table)
{
	uint32_t i;
#define LINE_NUMS	4

	gkt_printf("FACTORY_INSPECT: (%u) KEY FREQS", 
		window_factory_inspect.minor_stage);

	for (i = 0; i < GKT_CONFIG_KEYPAD_CHANNEL_NUMS; i++) {
		if (0 == (i % LINE_NUMS))
			gkt_printf("\nFACTORY_INSPECT: ");
		gkt_printf(" %u", freq_table[i]);
	}

	gkt_printf("\n");
}
#else
#define window_factory_inspect_key_show_freqs(freq_table)	do {} while(0)
#endif

#if defined(GKT_CONFIG_KEYPAD_SPT5115S_ENABLE)	\
	&& GKT_CONFIG_KEYPAD_SPT5115S_ENABLE
static int window_factory_inspect_key_do(uint32_t key)
{
	uint32_t key_freq_table[GKT_CONFIG_KEYPAD_CHANNEL_NUMS]={0};
	uint32_t i;
	int result;

	result = gkt_keypad_get_channel_freqs(key_freq_table);
	window_factory_inspect_key_show_freqs(key_freq_table);
	if (result == GKT_SUCCESS) {
		for (i = 0; i < GKT_CONFIG_KEYPAD_CHANNEL_NUMS; i++) {
			if (key_freq_table[i] > 0) 
			{
				if (!s_window_factory_inspect_key_freq_table[i]) {

					if (!((GKT_CONFIG_KEYPAD_NO_CONNECT_CHANNEL >> i) & 0x1)) {					
						gkt_window_voice_play(NULL, WINDOW_VOICE_COMBINED_ID(key), 0, NULL);
					}
					s_window_factory_inspect_key_freq_table[i] = 1;
					s_factory_inspect_key_ok_nums++;
					gkt_printf("ch[%d] ok num=%d\n",i, s_factory_inspect_key_ok_nums);
					if (GKT_CONFIG_KEYPAD_CHANNEL_NUMS == s_factory_inspect_key_ok_nums) {
						gkt_window_voice_play(NULL, WINDOW_VOICE_COMBINED_ID(please_uplift), 0, NULL);
						gkt_keypad_spt5115s_test_mode_control(GKT_KEYPAD_CTRL_DISABLE);
						return GKT_SUCCESS;
					}
				}
			}
		}
	}

	return GKT_EINPROCESS;
}

static int window_factory_inspect_key_init(uint32_t data)
{
	uint32_t key_freq_table[GKT_CONFIG_KEYPAD_CHANNEL_NUMS]={0};
	s_factory_inspect_key_ok_nums = 0;

	gkt_event_unmask_single(GKT_EVENT_KEY);
	gkt_keypad_spt5115s_test_mode_control(GKT_KEYPAD_CTRL_ENABLE);
	gkt_card_polling_control(0);
	gkt_keypad_get_channel_freqs(key_freq_table);
	window_factory_inspect_key_show_freqs(key_freq_table);
	
	gkt_window_voice_play(NULL, WINDOW_VOICE_COMBINED_ID(please_press_key), 0, NULL);

	return GKT_SUCCESS;
}
#else	
static int window_factory_inspect_key_do(uint32_t key)
{
	uint32_t key_freq_table[GKT_CONFIG_KEYPAD_CHANNEL_NUMS];
	uint32_t i, delta;
	int result;

	if (key < GKT_KEY_MAX) {
		if (s_window_factory_inspect_key_freq_table[key] > 0) {
			s_window_factory_inspect_key_freq_table[key] = 0;
			s_factory_inspect_key_ok_nums++;
#if defined(GKT_CONFIG_KEYPAD_NO_CONNECT_CHANNEL)			
			if ((GKT_CONFIG_KEYPAD_CHANNEL_NUMS - GKT_CONFIG_KEYPAD_NO_CONNECT_NUMS) == s_factory_inspect_key_ok_nums)
#else
			if (GKT_CONFIG_KEYPAD_CHANNEL_NUMS == s_factory_inspect_key_ok_nums)
#endif
			{
				gkt_window_voice_play(NULL, WINDOW_VOICE_COMBINED_ID(please_uplift), 0, NULL);
				return GKT_SUCCESS;
			}
		}
	}
	else {
		result = gkt_keypad_get_channel_freqs(key_freq_table);
		window_factory_inspect_key_show_freqs(key_freq_table);
		if(result == GKT_SUCCESS){
			for (i = 0; i < GKT_CONFIG_KEYPAD_CHANNEL_NUMS; i++) {
#if defined(GKT_CONFIG_KEYPAD_NO_CONNECT_CHANNEL)
				if ((((GKT_CONFIG_KEYPAD_NO_CONNECT_CHANNEL >> i) & 0x1) == 1)
					&& (s_window_factory_inspect_key_freq_table[i] != 0)) {
					s_window_factory_inspect_key_freq_table[i] = 0;
					s_factory_inspect_key_ok_nums++;
					continue;
				}
#endif
				if ((s_window_factory_inspect_key_freq_table[i] > 0) 
					&& key_freq_table[i] < s_window_factory_inspect_key_freq_table[i]) 
				{
					delta = s_window_factory_inspect_key_freq_table[i] - key_freq_table[i];
					if (delta >= WINDOW_FACTORY_INSPECT_KEY_DELTA_MIN) {
						s_window_factory_inspect_key_freq_table[i] = 0;
						s_factory_inspect_key_ok_nums++;

						if (GKT_CONFIG_KEYPAD_CHANNEL_NUMS == s_factory_inspect_key_ok_nums) {
							gkt_window_voice_play(NULL, WINDOW_VOICE_COMBINED_ID(please_uplift), 0, NULL);
							return GKT_SUCCESS;
						}
					}
				}
			}
		}
	}

	return GKT_EINPROCESS;
}

static int window_factory_inspect_key_init(uint32_t data)
{
	s_factory_inspect_key_ok_nums = 0;

	gkt_event_unmask_single(GKT_EVENT_KEY);
	gkt_keypad_get_channel_freqs(s_window_factory_inspect_key_freq_table);
	window_factory_inspect_key_show_freqs(s_window_factory_inspect_key_freq_table);

	gkt_window_voice_play(NULL, WINDOW_VOICE_COMBINED_ID(please_press_key), 0, NULL);

	return GKT_SUCCESS;
}
#endif

#define WINDOW_FACTORY_INSPECT_KEY_MINOR_STAGE_MAX	2
#define WINDOW_FACTORY_INSPECT_KEY_DO_INTERVAL	500
#define WINDOW_FACTORY_INSPECT_KEY_TIMEOUT	30000

/************************************************************
 * FPSENSOR
 ************************************************************/
static int window_factory_inspect_fpsensor_init(uint32_t data)
{
#if defined(GKT_CONFIG_FPS_FACTORY_INSPECT_ENABLE)	\
	&& GKT_CONFIG_FPS_FACTORY_INSPECT_ENABLE	
	return (int)gkt_fpsensor_self_inspect();
#else
	if (WINDOW_OPCODE_COMPATIBLE_FACTORY_INSPECT_3791 == window_factory_inspect.init_params)
		return GKT_SUCCESS;

	return (int)gkt_fpsensor_self_inspect();
#endif
}
#define window_factory_inspect_fpsensor_do	NULL
#define WINDOW_FACTORY_INSPECT_FPSENSOR_MINOR_STAGE_MAX	1
#define WINDOW_FACTORY_INSPECT_FPSENSOR_DO_INTERVAL	0
#define WINDOW_FACTORY_INSPECT_FPSENSOR_TIMEOUT	0

/************************************************************
 * RFID
 ************************************************************/
static int window_factory_inspect_rfid_init(uint32_t data)
{
#if defined(GKT_CONFIG_RFID_ENABLE) && GKT_CONFIG_RFID_ENABLE
#if defined(GKT_CONFIG_FACTORY_SELF_INSPECT_RFID_CLOSE) && GKT_CONFIG_FACTORY_SELF_INSPECT_RFID_CLOSE
	return GKT_SUCCESS;
#else
	int retval=GKT_SUCCESS;
	uint8_t rfid_type;
	
	gkt_keypad_control(GKT_KEYPAD_CTRL_DISABLE, 0);
	gkt_thread_sleep(100);

	gkt_get_rfid_type(&rfid_type);
	if (rfid_type < GKT_RFID_CHIP_TYPE_MAX) {
		if ((rfid_type == GKT_RFID_CHIP_TYPE_YC5018)
			|| (gp_window_unreset_data->rfid_standby_mode == GKT_RFID_STANBY_SOFT_POWEROFF)) {
			/*standby poweroff mode*/
			retval = (int)gkt_rfid_factory_inspect(1);
			if (retval != GKT_SUCCESS) {
				gkt_keypad_control(GKT_KEYPAD_CTRL_ENABLE, 0);	
				return retval;
			}

			if (rfid_type == GKT_RFID_CHIP_TYPE_YC5018) {
#if defined(GKT_CONFIG_RFID_YC5018) && GKT_CONFIG_RFID_YC5018
				uint32_t gain;
				uint32_t water_level;

				gkt_rfid_factory_gain_get(&gain);
				if ((gp_window_unreset_data->yc_rfid_gain != gain) 
					&& (gain != 0)) {
					gp_window_unreset_data->yc_rfid_gain = gain;
					gkt_printf("save card gain =0x%x\n",
						gp_window_unreset_data->yc_rfid_gain);	
					window_data_save();
				}
				
				gkt_rfid_factory_water_level_get(&water_level);
				if ((gp_window_unreset_data->yc_rfid_water_level_factory != water_level) 
					&& (water_level != 0)) {
					gp_window_unreset_data->yc_rfid_water_level_factory = (int)water_level;
					gkt_printf("save card calibrate level=0x%x\n",
							gp_window_unreset_data->yc_rfid_water_level_factory);		
					window_data_save();
				}
#endif
			}	
		}
		else {/*standby lpcd mode*/
			/*led all off */
			gkt_key_led_control(GKT_KEY_LED_CTRL_ENABLE, 0);
			gkt_thread_sleep(100);
			retval = (int)gkt_rfid_factory_inspect(0);
			if (retval == GKT_SUCCESS) {
				/*led all on */
				gkt_key_led_control(GKT_KEY_LED_CTRL_ENABLE, 1);
				gkt_thread_sleep(100);
				retval = (int)gkt_rfid_factory_inspect(1);
			}		
		}
	}
	gkt_keypad_control(GKT_KEYPAD_CTRL_ENABLE, 0);
	
	return retval;
#endif	
#else
	return GKT_SUCCESS;
#endif	
}
#define window_factory_inspect_rfid_do	NULL
#define WINDOW_FACTORY_INSPECT_RFID_MINOR_STAGE_MAX	1
#define WINDOW_FACTORY_INSPECT_RFID_DO_INTERVAL	0
#define WINDOW_FACTORY_INSPECT_RFID_TIMEOUT	0

/************************************************************
 * CARD
 ************************************************************/
static int window_factory_inspect_card_init(uint32_t data)
{
#if defined(GKT_CONFIG_RFID_ENABLE) && GKT_CONFIG_RFID_ENABLE
	int retval=GKT_SUCCESS;
	uint8_t rfid_type;
	
	gkt_get_rfid_type(&rfid_type);
	if (rfid_type < GKT_RFID_CHIP_TYPE_MAX) 
		return GKT_SUCCESS;
	else
		return GKT_EPARAM;

	retval = gkt_rfid_reset();
	return retval;
#else
	return GKT_SUCCESS;
#endif	
}
#define window_factory_inspect_card_do	NULL
#define WINDOW_FACTORY_INSPECT_CARD_MINOR_STAGE_MAX	1
#define WINDOW_FACTORY_INSPECT_CARD_DO_INTERVAL	0
#define WINDOW_FACTORY_INSPECT_CARD_TIMEOUT	0

/************************************************************
 * KEY FREQS
 ************************************************************/
#if defined(GKT_CONFIG_KEYPAD_SPT5115S_ENABLE)	\
	&& GKT_CONFIG_KEYPAD_SPT5115S_ENABLE
static int window_factory_inspect_key_freqs_init(uint32_t data)
{
	return GKT_SUCCESS;
}
static int window_factory_inspect_key_freqs_do(uint32_t key)
{
	return GKT_SUCCESS;
}
#else	
/* key channel freq dec/inc default settings */
#ifdef GKT_CONFIG_WINDOW_FACTORY_INSPECT_KEY_CAHNNEL_FREQ_DEFAULT_DEC_MAX
#define WINDOW_FACTORY_INSPECT_KEY_CAHNNEL_FREQ_DEFAULT_DEC_MAX	\
	GKT_CONFIG_WINDOW_FACTORY_INSPECT_KEY_CAHNNEL_FREQ_DEFAULT_DEC_MAX
#else
#define WINDOW_FACTORY_INSPECT_KEY_CAHNNEL_FREQ_DEFAULT_DEC_MAX	3000
#endif
#ifdef GKT_CONFIG_WINDOW_FACTORY_INSPECT_KEY_CAHNNEL_FREQ_DEFAULT_INC_MAX
#define WINDOW_FACTORY_INSPECT_KEY_CAHNNEL_FREQ_DEFAULT_INC_MAX	\
	GKT_CONFIG_WINDOW_FACTORY_INSPECT_KEY_CAHNNEL_FREQ_DEFAULT_INC_MAX
#else
#define WINDOW_FACTORY_INSPECT_KEY_CAHNNEL_FREQ_DEFAULT_INC_MAX	3000
#endif
#ifdef GKT_CONFIG_WINDOW_FACTORY_INSPECT_KEY_CAHNNEL_FREQ_NUMBER_OF_TIMES
#define WINDOW_FACTORY_INSPECT_KEY_CAHNNEL_FREQ_NUMBER_OF_TIMES	\
	GKT_CONFIG_WINDOW_FACTORY_INSPECT_KEY_CAHNNEL_FREQ_NUMBER_OF_TIMES
#else
#define WINDOW_FACTORY_INSPECT_KEY_CAHNNEL_FREQ_NUMBER_OF_TIMES	1
#endif

#define FACTORY_INSPECT_CAHNNEL_FREQ_VALID_TIMES	25
typedef struct _factory_inspect_key_freq {
	uint32_t	base_freqs[GKT_CONFIG_KEYPAD_CHANNEL_NUMS];
	uint32_t	freq_valid_times;
	uint32_t 	abnormal[GKT_CONFIG_KEYPAD_CHANNEL_NUMS];
} factory_inspect_key_freq_s;
static factory_inspect_key_freq_s s_factory_inspect_key_freq;
static int window_factory_inspect_key_freqs_init(uint32_t data)
{
	// TODO:Finding boards susceptible to voice interference
	if (WINDOW_OPCODE_COMPATIBLE_FACTORY_INSPECT_3791 == window_factory_inspect.init_params) {
		gkt_voice_output_playback_attr_s voice_params;
		voice_params.interval = 0;
		voice_params.times = 1;
		gkt_window_voice_play(NULL,
			WINDOW_VOICE_COMBINED_ID(please_press_pound_to_add_admin_user),
			0, &voice_params);
	}
	s_factory_inspect_key_freq.freq_valid_times = 0;
	for (uint32_t i = 0; i < GKT_CONFIG_KEYPAD_CHANNEL_NUMS; i++)
		s_factory_inspect_key_freq.abnormal[i] = 0;
	
	gkt_printf("factory_inspect_key: DEC_MAX(%u), INC_MAX(%u)\n",
					WINDOW_FACTORY_INSPECT_KEY_CAHNNEL_FREQ_DEFAULT_DEC_MAX, 
					WINDOW_FACTORY_INSPECT_KEY_CAHNNEL_FREQ_DEFAULT_INC_MAX);

	return gkt_keypad_get_channel_base_freqs(s_factory_inspect_key_freq.base_freqs);
}
static int window_factory_inspect_key_freqs_do(uint32_t key)
{
	uint32_t channel_freqs[GKT_CONFIG_KEYPAD_CHANNEL_NUMS];
	int delta, channel_delta[GKT_CONFIG_KEYPAD_CHANNEL_NUMS];
	uint32_t i, oor_nums;
	int retval;
	
	retval = gkt_keypad_get_channel_delta(channel_freqs, channel_delta, 1);
	if (GKT_SUCCESS == retval) {
		oor_nums = 0;
		for (i = 0; i < GKT_CONFIG_KEYPAD_CHANNEL_NUMS; i++) {
#if defined(GKT_CONFIG_KEYPAD_NO_CONNECT_CHANNEL)
			if (((GKT_CONFIG_KEYPAD_NO_CONNECT_CHANNEL >> i) & 0x1) == 1) 
				continue;
#endif
			delta = channel_delta[i];
			if (delta < 0) {
				if (-delta >= WINDOW_FACTORY_INSPECT_KEY_CAHNNEL_FREQ_DEFAULT_DEC_MAX) {
					gkt_error("factory_inspect_key: <OOR_LO> C(%u), BASE(%u), FREQ(%u)\n",
						i, s_factory_inspect_key_freq.base_freqs[i], channel_freqs[i]);
					
					s_factory_inspect_key_freq.abnormal[i]++;
					if (s_factory_inspect_key_freq.abnormal[i] == WINDOW_FACTORY_INSPECT_KEY_CAHNNEL_FREQ_NUMBER_OF_TIMES)
						oor_nums++;
				}
				else
					s_factory_inspect_key_freq.abnormal[i] = 0;
			}
			else {
				if (delta >= WINDOW_FACTORY_INSPECT_KEY_CAHNNEL_FREQ_DEFAULT_INC_MAX) {
					gkt_error("factory_inspect_key: <OOR_HI> C(%u), BASE(%u), FREQ(%u)\n",
						i, s_factory_inspect_key_freq.base_freqs[i], channel_freqs[i]);

					s_factory_inspect_key_freq.abnormal[i]++;
					if (s_factory_inspect_key_freq.abnormal[i] == WINDOW_FACTORY_INSPECT_KEY_CAHNNEL_FREQ_NUMBER_OF_TIMES)
						oor_nums++;
				}
				else
					s_factory_inspect_key_freq.abnormal[i] = 0;
			}
		}
#if defined(GKT_CONFIG_RFID_ENABLE) && GKT_CONFIG_RFID_ENABLE		
		gkt_rfid_control(GKT_RFID_CTRL_DISABLE, GKT_RFID_EXT_DATA_NONE);
#endif
		if (!oor_nums) {
			s_factory_inspect_key_freq.freq_valid_times++;
			if (FACTORY_INSPECT_CAHNNEL_FREQ_VALID_TIMES == s_factory_inspect_key_freq.freq_valid_times)
				return GKT_SUCCESS;
			else
				return GKT_EINPROCESS;
		}
		else
			return GKT_EUNDESIRED;
	}
	else {
		gkt_error("factory_inspect_key: sample channel freqs failed %d\n", retval);
	}

	return retval;
}
#endif
#define WINDOW_FACTORY_INSPECT_KEY_FREQS_MINOR_STAGE_MAX	2
#define WINDOW_FACTORY_INSPECT_KEY_FREQS_DO_INTERVAL	20
#define WINDOW_FACTORY_INSPECT_KEY_FREQS_TIMEOUT	0

#if  (!defined(GKT_CONFIG_KEYPAD_SPT5115S_ENABLE) || !GKT_CONFIG_KEYPAD_SPT5115S_ENABLE)	\
	&& defined(GKT_CONFIG_KEYPAD_NO_CONNECT_CHANNEL)
/************************************************************
 * NO CONNECT KEY CHANNEL FREQS
 ************************************************************/
#ifdef GKT_CONFIG_WINDOW_FACTORY_INSPECT_KEY_NO_CONNECT_CAHNNEL_FREQ_DEFAULT_MAX
#define WINDOW_FACTORY_INSPECT_KEY_NO_CONNECT_CAHNNEL_FREQ_DEFAULT_MAX	\
	GKT_CONFIG_WINDOW_FACTORY_INSPECT_KEY_NO_CONNECT_CAHNNEL_FREQ_DEFAULT_MAX
#else
#define WINDOW_FACTORY_INSPECT_KEY_NO_CONNECT_CAHNNEL_FREQ_DEFAULT_MAX	650000
#endif

typedef struct _factory_inspect_no_connect_key_freq {
	uint32_t	base_freqs[GKT_CONFIG_KEYPAD_CHANNEL_NUMS];
} factory_inspect_no_connect_key_freq_s;
static factory_inspect_no_connect_key_freq_s s_factory_inspect_no_connect_key_freq;
static int window_factory_inspect_no_connect_key_freqs_init(uint32_t data)
{
	return gkt_keypad_get_channel_base_freqs(s_factory_inspect_no_connect_key_freq.base_freqs);
}

static int window_factory_inspect_no_connect_key_freqs_do(uint32_t key)
{
	uint32_t i;
	int retval = GKT_SUCCESS;
	
	for (i = 0; i < GKT_CONFIG_KEYPAD_CHANNEL_NUMS; i++) {
		if (((GKT_CONFIG_KEYPAD_NO_CONNECT_CHANNEL >> i) & 0x1) == 1) {
			if (s_factory_inspect_no_connect_key_freq.base_freqs[i] < WINDOW_FACTORY_INSPECT_KEY_NO_CONNECT_CAHNNEL_FREQ_DEFAULT_MAX) {
				gkt_printf("no connect ch[%d]= %d < %d", 
					i, s_factory_inspect_no_connect_key_freq.base_freqs[i], 
					WINDOW_FACTORY_INSPECT_KEY_NO_CONNECT_CAHNNEL_FREQ_DEFAULT_MAX);
				return GKT_EUNDESIRED;
			}
		}
	}

	return retval;
}
#define WINDOW_FACTORY_INSPECT_NO_CONNECT_KEY_FREQS_MINOR_STAGE_MAX	2
#define WINDOW_FACTORY_INSPECT_NO_CONNECT_KEY_FREQS_DO_INTERVAL	20
#define WINDOW_FACTORY_INSPECT_NO_CONNECT_KEY_FREQS_TIMEOUT	0
#endif

/************************************************************
 * NETWORK
 ************************************************************/
#if WINDOW_FACTORY_INSPECT_NETWORK_ENABLE
static int window_factory_inspect_network_init(uint32_t data)
{
	gkt_unused(data);

	int retval;
	if (WINDOW_OPCODE_COMPATIBLE_FACTORY_INSPECT_3791 == window_factory_inspect.init_params)
		return GKT_SUCCESS;

	retval = gkt_network_self_test();
	if (GKT_SUCCESS == retval || GKT_EINPROCESS == retval)
		retval = GKT_EINPROCESS;
	else
		gkt_error("factory_inspect_network: send network test cmd failed %d\n", retval);

	return retval;
}
static int window_factory_inspect_network_do(uint32_t status)
{
	gkt_trace("window_factory_inspect_network_do: status(%u)\n", status);
	if (WINDOW_OPCODE_COMPATIBLE_FACTORY_INSPECT_3791 == window_factory_inspect.init_params)
		return GKT_SUCCESS;

	if (GKT_NETWORK_RUNNING_ST_TEST_COMPLETE != status) {
		window_factory_inspect.voice_id_network = WINDOW_VOICE_COMBINED_ID(another_error);
		switch (status) {
			case GKT_BB_STATUS_ERR_TEST_NO_UVC:
				window_factory_inspect.voice_id_network = WINDOW_VOICE_COMBINED_ID(invalid_error);
				break;
			case GKT_BB_STATUS_ERR_TEST_CONNECT_AP_FAIL:
				window_factory_inspect.voice_id_network = WINDOW_VOICE_COMBINED_ID(exist_error);
				break;
			case GKT_BB_STATUS_ERR_TEST_RSSI_WEAK:
				window_factory_inspect.voice_id_network = WINDOW_VOICE_COMBINED_ID(already_error);
				break;
			case GKT_BB_STATUS_ERR_UNKNOWN:
				window_factory_inspect.voice_id_network = WINDOW_VOICE_COMBINED_ID(another_error);
				break;
		}
		return GKT_ETIMEOUT;
	}
	return GKT_SUCCESS;
}
#define WINDOW_FACTORY_INSPECT_NETWORK_MINOR_STAGE_MAX	1
#define WINDOW_FACTORY_INSPECT_NETWORK_DO_INTERVAL	\
	(1000 * GKT_NETWORK_SELF_TEST_TIMEOUT_SEC)
#define WINDOW_FACTORY_INSPECT_NETWORK_TIMEOUT	0
#endif

/************************************************************
 * ITEM
 ************************************************************/
static const window_factory_inspect_item_s sc_factory_inspect_item_table[TEST_ITEM_MAX] = {
	WINDOW_FACTORY_INSPECT_ITEM_DEFINE(BATTERY_CALI, battery_cali),
	WINDOW_FACTORY_INSPECT_ITEM_DEFINE(KEY, key),
	WINDOW_FACTORY_INSPECT_ITEM_DEFINE(FPSENSOR, fpsensor),
	WINDOW_FACTORY_INSPECT_ITEM_DEFINE(CARD, card),
	WINDOW_FACTORY_INSPECT_ITEM_DEFINE(RFID, rfid),
	WINDOW_FACTORY_INSPECT_ITEM_DEFINE(KEY_FREQS, key_freqs),
#if  (!defined(GKT_CONFIG_KEYPAD_SPT5115S_ENABLE) || !GKT_CONFIG_KEYPAD_SPT5115S_ENABLE)	\
	&& defined(GKT_CONFIG_KEYPAD_NO_CONNECT_CHANNEL)
	WINDOW_FACTORY_INSPECT_ITEM_DEFINE(NO_CONNECT_KEY_FREQS, no_connect_key_freqs),
#endif	
#if WINDOW_FACTORY_INSPECT_NETWORK_ENABLE
	WINDOW_FACTORY_INSPECT_ITEM_DEFINE(NETWORK, network),
#endif
};
static void window_factory_inspect_handle_result(
					const window_factory_inspect_item_s *c_test_item, 
					int retval)
{
	if (GKT_SUCCESS == retval) {
		window_factory_inspect.minor_stage++;
		if ((window_factory_inspect.minor_stage < c_test_item->minor_stage_max)
			&& !window_factory_inspect.skip_subsequent_stage) 
		{
			if (c_test_item->do_interval > 0) {
				gkt_window_timer_set(TIMER_ID_DO, 
						c_test_item->do_interval, 
						0, window_factory_inspect.minor_stage);
			}

			if ((1 == window_factory_inspect.minor_stage)
				&& (c_test_item->timeout > 0))
			{
				gkt_window_timer_set(TIMER_ID_TIMEOUT, 
					c_test_item->timeout, 0, 0);
			}
		}
		else {
			window_factory_inspect.err_bits &= ~(1 << window_factory_inspect.major_stage);
			gkt_window_timer_clear(TIMER_ID_TIMEOUT);
			gkt_window_timer_set(TIMER_ID_START, 
					WINDOW_FACTORY_INSPECT_START_NEXT_INTERVAL, 0, 0);
		}
	}
	else if (GKT_EINPROCESS == retval) {
		if (c_test_item->do_interval > 0) {
			gkt_window_timer_set(TIMER_ID_DO, 
					c_test_item->do_interval, 
					0, window_factory_inspect.minor_stage);
		}
	}
	else {
		window_factory_inspect.err_bits |= 1 << window_factory_inspect.major_stage ;

		gkt_window_timer_clear(TIMER_ID_TIMEOUT);
		gkt_window_timer_set(TIMER_ID_START, 
				WINDOW_FACTORY_INSPECT_START_NEXT_INTERVAL, 0, 0);
	}
}

static void window_factory_inspect_show_result(uint32_t err_bits)
{
	gkt_voice_output_playback_attr_s voice_params;
	uint32_t voice_id=WINDOW_VOICE_COMBINED_ID(alarm);
//	uint32_t key_mask_bits;

	if (err_bits == 0){
		gp_window_unreset_data->factory_inspect_complete = 1;
		window_data_save();

		window_common_mask_except_cancel_ok();

		gkt_window_timer_clear(TIMER_ID_TIMEOUT);
		voice_params.interval = 500;
		voice_params.times = ~0;
		gkt_window_voice_play(NULL, WINDOW_VOICE_COMBINED_ID(operation_success),
				0, &voice_params);

		gkt_window_timer_set(TIMER_ID_EXIT, 5000, 0, 0);
		gkt_window_timeout_enable("factory_inspect - show_result");
	}
	else {
		window_common_mask_except_cancel_ok();

		gkt_window_timer_clear(TIMER_ID_TIMEOUT);
		
		for (window_factory_inspect.err_bits_ids=0; window_factory_inspect.err_bits_ids<TEST_ITEM_MAX; window_factory_inspect.err_bits_ids++) {
			if (err_bits & (1<<window_factory_inspect.err_bits_ids)) {
				voice_id = gc_window_factory_inspect_error_voice_ids[window_factory_inspect.err_bits_ids];
				voice_params.interval = 0;
				voice_params.times = 1;
				gkt_window_voice_play(NULL, voice_id, 0, &voice_params);
				window_factory_inspect.err_bits_ids++;
				if (window_factory_inspect.err_bits_ids == TEST_ITEM_MAX)
					window_factory_inspect.err_bits_ids = 0;
				gkt_window_timer_set(TIMER_ID_VOICE_TIMEOUT, 3000, 0, 0);
				break;
			}
		}
	}
}

static void window_factory_inspect_next(void)
{
	const window_factory_inspect_item_s *c_test_item;
	int retval;

	window_factory_inspect.major_stage++;
	if (window_factory_inspect.major_stage < TEST_ITEM_MAX) {
		gkt_printf("\nFACTORY_INSPECT: START - %u ...\n", window_factory_inspect.major_stage);

		c_test_item = &sc_factory_inspect_item_table[window_factory_inspect.major_stage];

		if (c_test_item->init_fn) {
			window_factory_inspect.minor_stage = 0;
			window_factory_inspect.skip_subsequent_stage = 0;
			retval = (*c_test_item->init_fn)(0);
			window_factory_inspect_handle_result(c_test_item, retval);
		}
		else
			gkt_window_timer_set(TIMER_ID_START, 
				WINDOW_FACTORY_INSPECT_START_NEXT_INTERVAL, 0, 0);
	}
	else {
		window_factory_inspect_show_result(window_factory_inspect.err_bits);
	}
}

static void window_factory_inspect_do(uint32_t data)
{
	const window_factory_inspect_item_s *c_test_item;
	int retval = GKT_SUCCESS;
		
	if (window_factory_inspect.major_stage < TEST_ITEM_MAX) {
		c_test_item = &sc_factory_inspect_item_table[window_factory_inspect.major_stage];
		if (*c_test_item->do_fn 
			&& (window_factory_inspect.minor_stage < c_test_item->minor_stage_max))
		{
			retval = (*c_test_item->do_fn)(data);
		}

		window_factory_inspect_handle_result(c_test_item, retval);
	}
}

static void window_factory_inspect_timeout(void)
{
	const window_factory_inspect_item_s *c_test_item;

	if (window_factory_inspect.major_stage < TEST_ITEM_MAX) {
		c_test_item = &sc_factory_inspect_item_table[window_factory_inspect.major_stage];
		window_factory_inspect_handle_result(c_test_item, GKT_ETIMEOUT);
	}
}

static int window_factory_inspect_event_handler(
					uint32_t major_type, uint32_t minor_type, 
					uint32_t widget_id, uint32_t data)
{
	gkt_voice_output_playback_attr_s voice_params;
	uint32_t number;
	
	switch (major_type) {
		case GKT_EVENT_WINDOW:
			if (GKT_WINDOW_INIT == minor_type) {
				window_factory_inspect.init_params = data;
				window_factory_inspect.major_stage = ~0;
				window_factory_inspect.err_bits = 0;
				window_factory_inspect.err_bits_ids = TEST_ITEM_MAX;
				gkt_window_system_standby_disable();
				gkt_window_timeout_disable("factory_inspect - INIT");
				//window_common_control_key_real_trim("factory_inspect - INIT", 0);
			}
			else if (GKT_WINDOW_ACTIVE == minor_type) {
				window_common_mask_all();
				gkt_key_led_control(GKT_KEY_LED_CTRL_ALL_ON, 1);

				gkt_window_timer_set(TIMER_ID_START, WINDOW_FACTORY_INSPECT_START_NEXT_INTERVAL, 0, 0);
				gkt_window_voice_stop(GKT_WINDOW_VOICE_F_UNINTERRUPT);
			}
			else if (GKT_WINDOW_INACTIVE == minor_type)
				gkt_key_led_control(GKT_KEY_LED_CTRL_ALL_ON, 0);
			else if (GKT_WINDOW_UNINIT == minor_type) {
				//window_common_control_key_real_trim("factory_inspect - UNINIT", 1);
				gkt_window_timeout_enable("factory_inspect - UNINIT");
				gkt_window_system_standby_enable();
				gkt_window_system_standby(1);
			}
			break;
		case GKT_EVENT_KEY:
			if (TEST_ITEM_KEY == window_factory_inspect.major_stage) {
				gkt_window_timer_clear(TIMER_ID_DO);
				window_factory_inspect_do(minor_type);
			}
			else if (window_factory_inspect.major_stage >= TEST_ITEM_MAX)
				return GKT_EVENT_HANDLE_CONTINUE;
			break;
#if WINDOW_FACTORY_INSPECT_NETWORK_ENABLE
		case GKT_EVENT_SYSTEM:
			if (TEST_ITEM_NETWORK == window_factory_inspect.major_stage) {
				if (GKT_WINDOW_SYSTEM_NETWORK == minor_type) {
					if (GKT_NETWORK_NOTIFY_TYPE_RUNNING_STATUS == widget_id) {
						gkt_window_timer_clear(TIMER_ID_DO);
						window_factory_inspect_do(data);
					}
				}
			}
			break;
#endif
		case GKT_EVENT_TIMER:
			if (TIMER_ID_START == minor_type)
				window_factory_inspect_next();
			else if (TIMER_ID_DO == minor_type) {
				if (data == window_factory_inspect.minor_stage)
					window_factory_inspect_do(~0);
			}
			else if (TIMER_ID_TIMEOUT == minor_type)
				window_factory_inspect_timeout();
			else if (TIMER_ID_VOICE_TIMEOUT == minor_type) {
				gkt_window_timer_clear(TIMER_ID_VOICE_TIMEOUT);
				if (window_factory_inspect.err_bits_ids != TEST_ITEM_MAX) {
					number = 0;
					
					do {	
						if (window_factory_inspect.err_bits & (1<<window_factory_inspect.err_bits_ids)) {
							voice_params.interval = 0;
							voice_params.times = 1;
							gkt_window_voice_play(NULL, 
								gc_window_factory_inspect_error_voice_ids[window_factory_inspect.err_bits_ids], 
								0, &voice_params);
							window_factory_inspect.err_bits_ids++;
							if (window_factory_inspect.err_bits_ids == TEST_ITEM_MAX)
								window_factory_inspect.err_bits_ids = 0;
							gkt_window_timer_set(TIMER_ID_VOICE_TIMEOUT, 3000, 0, 0);
							break;
						}
						
						if (window_factory_inspect.err_bits_ids == (TEST_ITEM_MAX-1))
							window_factory_inspect.err_bits_ids = 0;
						else
							window_factory_inspect.err_bits_ids++;
						number++;
					} while(number < TEST_ITEM_MAX);
				}
			}
			else if (TIMER_ID_EXIT == minor_type)
				gkt_window_exit();
			break;
	}
	
	return GKT_EVENT_HANDLE_COMPLETE;
}

GKT_WINDOW_DESC_DEFINE(factory_inspect);

#endif


